﻿#include "PoisonHugger.h"
#include "../../MirEnvir/Envir.h"
#include "../../../Shared/Functions/Functions.h"
#include "../../../Shared/ServerPackets.h"
#include "../../../Shared/Data/Stat.h"
#include "../DelayedAction.h"
#include "../../../Shared/Enums.h"
#include "../MapObject.h"
#include "../../Settings.h"

using namespace Server::MirDatabase;
using namespace Server::MirEnvir;
namespace S = ServerPackets;

namespace Server::MirObjects::Monsters
{

    PoisonHugger::PoisonHugger(MonsterInfo *info) : MonsterObject(info)
    {
        ExplosionTime = getEnvir()->getTime() + 1000 * 60 * 5;
    }

    bool PoisonHugger::InAttackRange()
    {
        return getCurrentMap() == getTarget()->getCurrentMap() && Functions::InRange(getCurrentLocation(), getTarget()->getCurrentLocation(), AttackRange);
    }

    void PoisonHugger::ProcessTarget()
    {
        if (!getCanAttack())
        {
            return;
        }

        if (getTarget() == nullptr || getEnvir()->getTime() > ExplosionTime || !getTarget()->IsAttackTarget(this))
        {
            Die();
            return;
        }

        bool ranged = !Functions::InRange(getCurrentLocation(), getTarget()->getCurrentLocation(), 1);

        if (InAttackRange())
        {
            if (ranged)
            {
                if (getEnvir()->Random->Next(5) == 0)
                {
                    setDirection(Functions::DirectionFromPoint(getCurrentLocation(), getTarget()->getCurrentLocation()));
                    S::ObjectRangeAttack *tempVar = new S::ObjectRangeAttack();
                    tempVar->ObjectID = ObjectID;
                    tempVar->Direction = getDirection();
                    tempVar->Location = getCurrentLocation();
                    tempVar->TargetID = getTarget()->ObjectID;
                    Broadcast(tempVar);

                    ActionTime = getEnvir()->getTime() + 300;
                    AttackTime = getEnvir()->getTime() + AttackSpeed;

                    int damage = GetAttackPower(Stats[Stat::MinDC], Stats[Stat::MaxDC]);
                    if (damage == 0)
                    {
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
                        return;
                    }

                    int delay = Functions::MaxDistance(getCurrentLocation(), getTarget()->getCurrentLocation()) * 50 + 500; //50 MS per Step

                    DelayedAction *action = new DelayedAction(DelayedType::RangeDamage, getEnvir()->getTime() + delay, {getTarget(), damage, DefenceType::ACAgility});
                    ActionList.push_back(action);

//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
                    return;
                }
                else
                {
                    MoveTo(getTarget()->getCurrentLocation());
                }
            }
            else
            {
                Die();
            }
        }

        if (getEnvir()->getTime() < ShockTime)
        {
            setTarget(nullptr);
            return;
        }

        MoveTo(getTarget()->getCurrentLocation());
    }

    void PoisonHugger::Die()
    {
        std::vector<MapObject*> targets = FindAllTargets(1, getCurrentLocation());

        for (int i = 0; i < targets.size(); i++)
        {
            DelayedAction tempVar(DelayedType::Die, getEnvir()->getTime() + 500, {targets[i], GetAttackPower(Stats[Stat::MinDC], Stats[Stat::MaxDC]), DefenceType::ACAgility});
            ActionList.push_back(&tempVar);
        }

        MonsterObject::Die();
    }

    void PoisonHugger::CompleteDeath(std::vector<std::any> &data)
    {
        MapObject *target = std::any_cast<MapObject*>(data[0]);
        int damage = std::any_cast<int>(data[1]);
        DefenceType defence = std::any_cast<DefenceType>(data[2]);

        if (target->Attacked(this, damage, defence) <= 0)
        {
            return;
        }

        if (getEnvir()->Random->Next(Settings::PoisonResistWeight) >= target->Stats[Stat::PoisonResist])
        {
            if (getEnvir()->Random->Next(5) == 0)
            {
                Poison *tempVar = new Poison(), *this;
                tempVar->Owner = this;
                tempVar->Duration = 5;
                tempVar->PType = PoisonType::Green;
                tempVar->Value = GetAttackPower(Stats[Stat::MinSC], Stats[Stat::MaxSC]);
                tempVar->TickSpeed = 2000;
                target->ApplyPoison(tempVar, this);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
            }
        }
    }
}
